package com.yangfan.juc.atomic;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @description:  AtomicStampedReference 类主要能够解决  CAS 的 ABA 问题
 * @author: yangfan
 * @date: Created in 2020/3/21 0021 16:23
 * @modified By:
 *
 * ABA 问题：
 *
 *      value = 'A'
 *      Thread t1 把 value 改成了  B  然后 有给改成了 A
 *      Thread t2 此时想把 value 改成 C 他在 内存中获取 到 value 为 A 所以直接 把 value 改成了 C
 *      但 value 已经被 t1 线程改成了 B 又 改成了 A 这个过程 是应该被避免的 就像 小偷 偷了你的钱，又偷偷给你送回来一样。已经发生的事情不允许 就这么算了！
 *      解决方案  一个不标记 版本号： stamp 只要数据被改动过 就需要去 累加一次 修改的时候版本不一致 也不能修改。
 *
 */
public class AtomicStampedReferenceTest {


    private static AtomicStampedReference<Integer> atomic = new AtomicStampedReference<>(100, 0);


    public static void main(String[] args) {


        Thread t1 = new Thread(){
            @Override
            public void run() {


                ExecutorService executorService = Executors.newFixedThreadPool(5);
                ExecutorService exec = Executors.newCachedThreadPool();
                exec.execute( () -> {

                });


                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                boolean b = atomic.compareAndSet(100, 101, atomic.getStamp(), atomic.getStamp() + 1);
                System.out.println(b);
                b = atomic.compareAndSet(101, 100, atomic.getStamp(), atomic.getStamp()+1);
                System.out.println(b);
            }
        };


        Thread t2 = new Thread(){
            @Override
            public void run() {

                int stamp = atomic.getStamp();//提前把 标记获取

                //等待2毫秒已经被 t1 线程改了 所以下面 修改肯定不成功
                try {
                    TimeUnit.SECONDS.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                boolean b = atomic.compareAndSet(100, 110, stamp, stamp + 1);
                System.out.println(b);
            }
        };


        t1.start();
        t2.start();


    }




}
